From 33feceb1573cbb6ba7fb326bb7872de75bca6b9e Mon Sep 17 00:00:00 2001
From: mancha <mancha1 AT zoho DOT com>
Date: Wed, 18 Feb 2015
Subject: Fix account validation with glibc crypt

Starting with glibc 2.17, crypt() can return NULL which can cause
xrdp-sesman to segfault. This patch backports upstream's fix for
this as well as changes auth_userpass so it can validate SHA-256
and SHA-512 hashed passwords.

---
 sesman/verify_user.c |   87 ++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 52 deletions(-)

--- a/sesman/verify_user.c
+++ b/sesman/verify_user.c
@@ -51,64 +51,47 @@ auth_account_disabled(struct spwd* stp);
 long DEFAULT_CC
 auth_userpass(char* user, char* pass)
 {
-  char salt[13] = "$1$";
-  char hash[35] = "";
-  char* encr = 0;
-  struct passwd* spw;
-  struct spwd* stp;
-  int saltcnt = 0;
-
-  spw = getpwnam(user);
-  if (spw == 0)
-  {
-    return 0;
-  }
-  if (g_strncmp(spw->pw_passwd, "x", 3) == 0)
-  {
-    /* the system is using shadow */
-    stp = getspnam(user);
-    if (stp == 0)
+    const char *encr;
+    const char *epass;
+    struct passwd *spw;
+    struct spwd *stp;
+
+    spw = getpwnam(user);
+
+    if (spw == 0)
+    {
+        return 0;
+    }
+
+    if (g_strncmp(spw->pw_passwd, "x", 3) == 0)
     {
-      return 0;
+        /* the system is using shadow */
+        stp = getspnam(user);
+
+        if (stp == 0)
+        {
+            return 0;
+        }
+
+        if (1 == auth_account_disabled(stp))
+        {
+            log_message(&(g_cfg->log), LOG_LEVEL_INFO, "account %s is disabled", user);
+            return 0;
+        }
+
+        encr = stp->sp_pwdp;
     }
-    if (1==auth_account_disabled(stp))
+    else
     {
-      log_message(&(g_cfg->log), LOG_LEVEL_INFO, "account %s is disabled", user);
-      return 0;
+        /* old system with only passwd */
+        encr = spw->pw_passwd;
     }
-    g_strncpy(hash, stp->sp_pwdp, 34);
-  }
-  else
-  {
-    /* old system with only passwd */
-    g_strncpy(hash, spw->pw_passwd, 34);
-  }
-  hash[34] = '\0';
-  if (g_strncmp(hash, "$1$", 3) == 0)
-  {
-    /* gnu style crypt(); */
-    saltcnt = 3;
-    while ((hash[saltcnt] != '$') && (saltcnt < 11))
+    epass = crypt(pass, encr);
+    if (epass == 0)
     {
-      salt[saltcnt] = hash[saltcnt];
-      saltcnt++;
+        return 0;
     }
-    salt[saltcnt] = '$';
-    salt[saltcnt + 1] = '\0';
-  }
-  else
-  {
-    /* classic two char salt */
-    salt[0] = hash[0];
-    salt[1] = hash[1];
-    salt[2] = '\0';
-  }
-  encr = crypt(pass,salt);
-  if (g_strncmp(encr, hash, 34) != 0)
-  {
-    return 0;
-  }
-  return 1;
+    return (strcmp(encr, epass) == 0);
 }
 
 /******************************************************************************/
